/*!
    \file  pcram.c
    \brief pcram driver

    \version 2020-8-4, V1.0.0, firmware for RV300+
*/

/*
    Copyright (c);2019-2022;Wiscom System;

	All rights reserved.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the Wiscom System nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

#define PageSize              256
#define SPI_TIME_US           500
#include <stdio.h>
#include "csg_sdk_hal.h"
#include "csg_sdk_soc.h"
#include "pcram.h"

#define SPI_SCK_1    LGPIO_WriteBit(LGPIO,1<<26,1)            /* SCK = 1 */
#define SPI_SCK_0    LGPIO_WriteBit(LGPIO,1<<26,0)        /* SCK = 0 */

#define SPI_MOSI_1    LGPIO_WriteBit(LGPIO,1<<27,1)            /* MOSI = 1 */
#define SPI_MOSI_0    LGPIO_WriteBit(LGPIO,1<<27,0)        /* MOSI = 0 */

#define SPI_PCRAM_CS_ON    LGPIO_WriteBit(LGPIO,1<<18,0)            /* CS = 0 */
#define SPI_PCRAM_CS_OFF    LGPIO_WriteBit(LGPIO,1<<18,1)        /* CS = 1 */

#define SPI_READ_MISO    LGPIO_ReadInputDataBit(LGPIO, 1<<28)    /* 读MISO口线状态 */

#define Dummy_Byte    0xFF    //读取时MISO发送的数据，可以为任意数据

void EXMC_PCRAM_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint32_t NumByteToWrite)
{
//  delay_1ms(1000);
  uint32_t i = 0;
  uint32_t WriteRealAddr=0;
  uint32_t Write32_num=0;
  uint32_t Temp_Value=0;
  uint8_t Addr_start_Offset = 0;
  uint8_t Addr_end_Offset = 0;
  uint32_t Num1, Num2, Num3, Num4;
  Addr_start_Offset=WriteAddr%4;
  Addr_end_Offset=(4-(Addr_start_Offset+NumByteToWrite)%4)%4;
  if(Addr_end_Offset)
  {
    Write32_num=(Addr_start_Offset+NumByteToWrite)/4+1;
  }
  else
  {
    Write32_num=(Addr_start_Offset+NumByteToWrite)/4;
  }
  WriteRealAddr = WriteAddr-Addr_start_Offset;
  if(Write32_num==1)
  {
    switch (Addr_start_Offset)
    {
      case 0:
      {
        if(Addr_end_Offset==0)
        {
          Num1=*pBuffer;
          Num2=*(pBuffer+1);
          Num3=*(pBuffer+2);
          Num4=*(pBuffer+3);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else if(Addr_end_Offset==1)
        {
          Num1=*pBuffer;
          Num2=*(pBuffer+1);
          Num3=*(pBuffer+2);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else if(Addr_end_Offset==2)
        {
          Num1=*pBuffer;
          Num2=*(pBuffer+1);
          Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else
        {
          Num1=*pBuffer;
          Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
          Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        break;
      }
      case 1:
      {
        if(Addr_end_Offset==0)
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=*pBuffer;
          Num3=*(pBuffer+1);
          Num4=*(pBuffer+2);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else if(Addr_end_Offset==1)
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=*pBuffer;
          Num3=*(pBuffer+1);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=*pBuffer;
          Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        break;
      }
      case 2:
      {
        if(Addr_end_Offset==0)
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
          Num3=*pBuffer;
          Num4=*(pBuffer+1);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
          Num3=*pBuffer;
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        break;
      }
      case 3:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
        Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
        Num4=*pBuffer;
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
    }
  }
  else
  {
    switch (Addr_start_Offset)
    {
      case 0:
      {
        Num1=*pBuffer;
        Num2=*(pBuffer+1);
        Num3=*(pBuffer+2);
        Num4=*(pBuffer+3);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
      case 1:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=*pBuffer;
        Num3=*(pBuffer+1);
        Num4=*(pBuffer+2);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
      case 2:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
        Num3=*pBuffer;
        Num4=*(pBuffer+1);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
      case 3:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
        Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
        Num4=*pBuffer;
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
    }
    for(i=1;i<Write32_num-1;i++)
    {
      Num1=*(pBuffer+i*4-Addr_start_Offset);
      Num2=*(pBuffer+i*4-Addr_start_Offset+1);
      Num3=*(pBuffer+i*4-Addr_start_Offset+2);
      Num4=*(pBuffer+i*4-Addr_start_Offset+3);
      Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
      REG32(WriteRealAddr+i*4) = Temp_Value;
    }
    switch (Addr_end_Offset)
    {
      case 0:
      {
        Num1=*(pBuffer+i*4-Addr_start_Offset);
        Num2=*(pBuffer+i*4-Addr_start_Offset+1);
        Num3=*(pBuffer+i*4-Addr_start_Offset+2);
        Num4=*(pBuffer+i*4-Addr_start_Offset+3);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr+(Write32_num-1)*4) = Temp_Value;
        break;
      }
      case 1:
      {
        Num1=*(pBuffer+i*4-Addr_start_Offset);
        Num2=*(pBuffer+i*4-Addr_start_Offset+1);
        Num3=*(pBuffer+i*4-Addr_start_Offset+2);
        Num4=(REG32(WriteRealAddr+(Write32_num-1)*4)&0x000000FF);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr+(Write32_num-1)*4) = Temp_Value;
        break;
      }
      case 2:
      {
        Num1=*(pBuffer+i*4-Addr_start_Offset);
        Num2=*(pBuffer+i*4-Addr_start_Offset+1);
        Num3=((REG32(WriteRealAddr+(Write32_num-1)*4)&0x0000FF00)>>8);
        Num4=(REG32(WriteRealAddr+(Write32_num-1)*4)&0x000000FF);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr+(Write32_num-1)*4) = Temp_Value;
        break;
      }
      case 3:
      {
        Num1=*(pBuffer+i*4-Addr_start_Offset);
        Num2=((REG32(WriteRealAddr+(Write32_num-1)*4)&0x00FF0000)>>16);
        Num3=((REG32(WriteRealAddr+(Write32_num-1)*4)&0x0000FF00)>>8);
        Num4=(REG32(WriteRealAddr+(Write32_num-1)*4)&0x000000FF);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr+(Write32_num-1)*4) = Temp_Value;
        break;
      }
    }
  }
}

void EXMC_PCRAM_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
{
  uint32_t i = 0;
  uint32_t ReadRealAddr=0;
  uint32_t Read32_num=0;
  uint8_t Addr_start_Offset = 0;
  uint8_t Addr_end_Offset = 0;
  uint32_t Temp_value = 0;
  uint32_t Temp_addr = 0;
  uint32_t Temp_case = 0;
  uint32_t Num1, Num2, Num3, Num4;
  Addr_start_Offset=ReadAddr%4;
  Addr_end_Offset=(4-(Addr_start_Offset+NumByteToRead)%4)%4;
  if((Addr_start_Offset+NumByteToRead)%4)
  {
    Read32_num=(Addr_start_Offset+NumByteToRead)/4+1;
  }
  else
  {
    Read32_num=(Addr_start_Offset+NumByteToRead)/4;
  }
  ReadRealAddr = ReadAddr-Addr_start_Offset;
  // ////////////////////////////////Temp test
  // for(i=0;i<NumByteToRead;i=i+4)
  // {
  //   Temp_value=REG32(ReadRealAddr+i);
  //   *(pBuffer+i)=((Temp_value&0xFF000000)>>24);
  //   *(pBuffer+i+1)=((Temp_value&0x00FF0000)>>16);
  //   *(pBuffer+i+2)=((Temp_value&0x0000FF00)>>8);
  //   *(pBuffer+i+3)=(Temp_value&0x000000FF);
  // }
  // ////////////////////////////////Temp test
  if(Read32_num==1)
  {
    Temp_value=REG32(ReadRealAddr);
    switch (Addr_start_Offset)
    {
      case 0:
      {
        if(Addr_end_Offset==0)
        {
          *(pBuffer)=((Temp_value&0xFF000000)>>24);
          *(pBuffer+1)=((Temp_value&0x00FF0000)>>16);
          *(pBuffer+2)=((Temp_value&0x0000FF00)>>8);
          *(pBuffer+3)=(Temp_value&0x000000FF);
        }
        else if(Addr_end_Offset==1)
        {
          *(pBuffer)=((Temp_value&0xFF000000)>>24);
          *(pBuffer+1)=((Temp_value&0x00FF0000)>>16);
          *(pBuffer+2)=((Temp_value&0x0000FF00)>>8);
        }
        else if(Addr_end_Offset==2)
        {
          *(pBuffer)=((Temp_value&0xFF000000)>>24);
          *(pBuffer+1)=((Temp_value&0x00FF0000)>>16);
        }
        else
        {
          *(pBuffer)=((Temp_value&0xFF000000)>>24);
        }
        break;
      }
      case 1:
      {
        if(Addr_end_Offset==0)
        {
          *(pBuffer)=((Temp_value&0x00FF0000)>>16);
          *(pBuffer+1)=((Temp_value&0x0000FF00)>>8);
          *(pBuffer+2)=(Temp_value&0x000000FF);
        }
        else if(Addr_end_Offset==1)
        {
          *(pBuffer)=((Temp_value&0x00FF0000)>>16);
          *(pBuffer+1)=((Temp_value&0x0000FF00)>>8);
        }
        else
        {
          *(pBuffer)=((Temp_value&0x00FF0000)>>16);
        }
        break;
      }
      case 2:
      {
        if(Addr_end_Offset==0)
        {
          *(pBuffer)=((Temp_value&0x0000FF00)>>8);
          *(pBuffer+1)=(Temp_value&0x000000FF);
        }
        else
        {
          *(pBuffer)=((Temp_value&0x0000FF00)>>8);
        }
        break;
      }
      case 3:
      {
        *(pBuffer)=(Temp_value&0x000000FF);
        break;
      }
    }
  }
  else
  {
    Temp_value=REG32(ReadRealAddr);
    switch (Addr_start_Offset)
    {
      case 0:
      {
        *(pBuffer)=((Temp_value&0xFF000000)>>24);
        *(pBuffer+1)=((Temp_value&0x00FF0000)>>16);
        *(pBuffer+2)=((Temp_value&0x0000FF00)>>8);
        *(pBuffer+3)=(Temp_value&0x000000FF);
        break;
      }
      case 1:
      {
        *(pBuffer)=((Temp_value&0x00FF0000)>>16);
        *(pBuffer+1)=((Temp_value&0x0000FF00)>>8);
        *(pBuffer+2)=(Temp_value&0x000000FF);
        break;
      }
      case 2:
      {
        *(pBuffer)=((Temp_value&0x0000FF00)>>8);
        *(pBuffer+1)=(Temp_value&0x000000FF);
        break;
      }
      case 3:
      {
        *(pBuffer)=(Temp_value&0x000000FF);
        break;
      }
    }
    for(i=1;i<Read32_num-1;i++)
    {
      Temp_value=REG32(ReadRealAddr+i*4);
      *(pBuffer+i*4-Addr_start_Offset)=((Temp_value&0xFF000000)>>24);
      *(pBuffer+i*4-Addr_start_Offset+1)=((Temp_value&0x00FF0000)>>16);
      *(pBuffer+i*4-Addr_start_Offset+2)=((Temp_value&0x0000FF00)>>8);
      *(pBuffer+i*4-Addr_start_Offset+3)=(Temp_value&0x000000FF);
    }
    Temp_value=REG32(ReadRealAddr+i*4);
    switch (Addr_end_Offset)
    {
      case 0:
      {
        *(pBuffer+i*4-Addr_start_Offset)=((Temp_value&0xFF000000)>>24);
        *(pBuffer+i*4-Addr_start_Offset+1)=((Temp_value&0x00FF0000)>>16);
        *(pBuffer+i*4-Addr_start_Offset+2)=((Temp_value&0x0000FF00)>>8);
        *(pBuffer+i*4-Addr_start_Offset+3)=(Temp_value&0x000000FF);
        break;
      }
      case 1:
      {
        *(pBuffer+i*4-Addr_start_Offset)=((Temp_value&0xFF000000)>>24);
        *(pBuffer+i*4-Addr_start_Offset+1)=((Temp_value&0x00FF0000)>>16);
        *(pBuffer+i*4-Addr_start_Offset+2)=((Temp_value&0x0000FF00)>>8);
        break;
      }
      case 2:
      {
        *(pBuffer+i*4-Addr_start_Offset)=((Temp_value&0xFF000000)>>24);
        *(pBuffer+i*4-Addr_start_Offset+1)=((Temp_value&0x00FF0000)>>16);
        break;
      }
      case 3:
      {
        *(pBuffer+i*4-Addr_start_Offset)=((Temp_value&0xFF000000)>>24);
        break;
      }
    }
  }
  // for(i=0;i<NumByteToRead;i++)
  // {
  //   Temp_case=(i+Addr_start_Offset)%4;
  //   switch(Temp_case)
  //   {
  //     Temp_addr=ReadRealAddr+(i+Addr_start_Offset)/4;
  //     Temp_value=REG32(Temp_addr);
  //     case 0:
  //     {

  //       *(pBuffer+i)=((Temp_value&0xFF000000)>>24);
  //       break;
  //     }
  //     case 1:
  //     {
  //       *(pBuffer+i)=((Temp_value&0x00FF0000)>>16);
  //       break;
  //     }
  //     case 2:
  //     {
  //       *(pBuffer+i)=((Temp_value&0x0000FF00)>>8);
  //       break;
  //     }
  //     case 3:
  //     {
  //       *(pBuffer+i)=(Temp_value&0x000000FF);
  //       break;
  //     }
  //   }
  // }
}

//void EXMC_PCRAM_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint32_t NumByteToRead)
//{
//  uint32_t i = 0;
//  ReadAddr += BANK_SRAM_ADDR;
//  //printf("start addr1: %p \r\n", ReadAddr);
//
//  uint8_t mother;
//  while(NumByteToRead--){
//      mother = (*(__IO uint8_t*)(ReadAddr));
//      *pBuffer = mother;
//      pBuffer++;
//      ReadAddr++;
//  }
//
//
////   for(i = 0; i < NumByteToRead; i++){
////      *(pBuffer+i)=(*(__IO uint8_t*)(ReadAddr+i));
////      
////   }
//
//}
void PCRAM_iomux_config(void)
{
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_0_IOF_OVAL, 59, GMC0_GMC_ADDR_0_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_1_IOF_OVAL, 60, GMC0_GMC_ADDR_1_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_2_IOF_OVAL, 61, GMC0_GMC_ADDR_2_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_3_IOF_OVAL, 62, GMC0_GMC_ADDR_3_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_4_IOF_OVAL, 63, GMC0_GMC_ADDR_4_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_5_IOF_OVAL, 64, GMC0_GMC_ADDR_5_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_6_IOF_OVAL, 65, GMC0_GMC_ADDR_6_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_7_IOF_OVAL, 66, GMC0_GMC_ADDR_7_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_8_IOF_OVAL, 67, GMC0_GMC_ADDR_8_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_9_IOF_OVAL, 68, GMC0_GMC_ADDR_9_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_10_IOF_OVAL, 69, GMC0_GMC_ADDR_10_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_11_IOF_OVAL, 70, GMC0_GMC_ADDR_11_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_12_IOF_OVAL, 71, GMC0_GMC_ADDR_12_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_13_IOF_OVAL, 72, GMC0_GMC_ADDR_13_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_14_IOF_OVAL, 73, GMC0_GMC_ADDR_14_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_15_IOF_OVAL, 74, GMC0_GMC_ADDR_15_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_16_IOF_OVAL, 75, GMC0_GMC_ADDR_16_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_17_IOF_OVAL, 76, GMC0_GMC_ADDR_17_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_18_IOF_OVAL, 77, GMC0_GMC_ADDR_18_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_19_IOF_OVAL, 78, GMC0_GMC_ADDR_19_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_20_IOF_OVAL, 79, GMC0_GMC_ADDR_20_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_21_IOF_OVAL, 80, GMC0_GMC_ADDR_21_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_22_IOF_OVAL, 81, GMC0_GMC_ADDR_22_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_23_IOF_OVAL, 82, GMC0_GMC_ADDR_23_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_24_IOF_OVAL, 83, GMC0_GMC_ADDR_24_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_ADDR_25_IOF_OVAL, 84, GMC0_GMC_ADDR_25_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_0_IOF_OVAL, 85, GMC0_GMC_DQ_0_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_1_IOF_OVAL, 86, GMC0_GMC_DQ_1_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_2_IOF_OVAL, 87, GMC0_GMC_DQ_2_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_3_IOF_OVAL, 88, GMC0_GMC_DQ_3_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_4_IOF_OVAL, 89, GMC0_GMC_DQ_4_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_5_IOF_OVAL, 90, GMC0_GMC_DQ_5_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_6_IOF_OVAL, 91, GMC0_GMC_DQ_6_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_7_IOF_OVAL, 92, GMC0_GMC_DQ_7_HS_SEL, 0, 0);

    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_8_IOF_OVAL, 93, GMC0_GMC_DQ_8_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_9_IOF_OVAL, 94, GMC0_GMC_DQ_9_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_10_IOF_OVAL, 95, GMC0_GMC_DQ_10_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_11_IOF_OVAL, 96, GMC0_GMC_DQ_11_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_12_IOF_OVAL, 97, GMC0_GMC_DQ_12_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_13_IOF_OVAL, 98, GMC0_GMC_DQ_13_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_14_IOF_OVAL, 99, GMC0_GMC_DQ_14_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_15_IOF_OVAL, 100, GMC0_GMC_DQ_15_HS_SEL, 0, 0);

    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_16_IOF_OVAL, 101, GMC0_GMC_DQ_16_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_17_IOF_OVAL, 0, GMC0_GMC_DQ_17_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_18_IOF_OVAL, 1, GMC0_GMC_DQ_18_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_19_IOF_OVAL, 2, GMC0_GMC_DQ_19_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_20_IOF_OVAL, 3, GMC0_GMC_DQ_20_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_21_IOF_OVAL, 4, GMC0_GMC_DQ_21_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_22_IOF_OVAL, 5, GMC0_GMC_DQ_22_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_23_IOF_OVAL, 6, GMC0_GMC_DQ_23_HS_SEL, 0, 0);

    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_24_IOF_OVAL, 7, GMC0_GMC_DQ_24_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_25_IOF_OVAL, 8, GMC0_GMC_DQ_25_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_26_IOF_OVAL, 9, GMC0_GMC_DQ_26_HS_SEL, 0, 0);
    // //iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_27_IOF_OVAL, 10, GMC0_GMC_DQ_27_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_28_IOF_OVAL, 11, GMC0_GMC_DQ_28_HS_SEL, 0, 0);
    // //iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_29_IOF_OVAL, 12, GMC0_GMC_DQ_29_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_30_IOF_OVAL, 13, GMC0_GMC_DQ_30_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_GMC_DQ_31_IOF_OVAL, 14, GMC0_GMC_DQ_31_HS_SEL, 0, 0);

    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_0_IOF_IVAL, 85, GMC0_GMC_DQ_0_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_1_IOF_IVAL, 86, GMC0_GMC_DQ_1_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_2_IOF_IVAL, 87, GMC0_GMC_DQ_2_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_3_IOF_IVAL, 88, GMC0_GMC_DQ_3_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_4_IOF_IVAL, 89, GMC0_GMC_DQ_4_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_5_IOF_IVAL, 90, GMC0_GMC_DQ_5_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_6_IOF_IVAL, 91, GMC0_GMC_DQ_6_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_7_IOF_IVAL, 92, GMC0_GMC_DQ_7_HS_SEL, 0, 0);

    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_8_IOF_IVAL, 93, GMC0_GMC_DQ_8_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_9_IOF_IVAL, 94, GMC0_GMC_DQ_9_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_10_IOF_IVAL, 95, GMC0_GMC_DQ_10_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_11_IOF_IVAL, 96, GMC0_GMC_DQ_11_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_12_IOF_IVAL, 97, GMC0_GMC_DQ_12_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_13_IOF_IVAL, 99, GMC0_GMC_DQ_13_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_14_IOF_IVAL, 100, GMC0_GMC_DQ_14_HS_SEL, 0, 0);
    iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_15_IOF_IVAL, 101, GMC0_GMC_DQ_15_HS_SEL, 0, 0);

    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_16_IOF_IVAL, 102, GMC0_GMC_DQ_16_HS_SEL, 0, 0);
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_17_IOF_IVAL, 32, GMC0_GMC_DQ_17_HS_SEL, 0, 0);
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_18_IOF_IVAL, 33, GMC0_GMC_DQ_18_HS_SEL, 0, 0);
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_19_IOF_IVAL, 34, GMC0_GMC_DQ_19_HS_SEL, 0, 0);  // also JTAG_TMS
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_20_IOF_IVAL, 35, GMC0_GMC_DQ_20_HS_SEL, 0, 0);  // also JTAG_TCK
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_21_IOF_IVAL, 36, GMC0_GMC_DQ_21_HS_SEL, 0, 0);  // also JTAG_TDO
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_22_IOF_IVAL, 37, GMC0_GMC_DQ_22_HS_SEL, 0, 0);
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_23_IOF_IVAL, 38, GMC0_GMC_DQ_23_HS_SEL, 0, 0);

    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_24_IOF_IVAL, 39, GMC0_GMC_DQ_24_HS_SEL, 0, 0);
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_25_IOF_IVAL, 40, GMC0_GMC_DQ_25_HS_SEL, 0, 0);
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_26_IOF_IVAL, 41, GMC0_GMC_DQ_26_HS_SEL, 0, 0);
    // //iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_27_IOF_IVAL, 42, GMC0_GMC_DQ_27_HS_SEL, 0, 0); // also UART_RX
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_28_IOF_IVAL, 43, GMC0_GMC_DQ_28_HS_SEL, 0, 0);   // also JTAG_TDI
    // //iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_29_IOF_IVAL, 44, GMC0_GMC_DQ_29_HS_SEL, 0, 0); // also UART_TX
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_30_IOF_IVAL, 45, GMC0_GMC_DQ_30_HS_SEL, 0, 0);
    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_GMC_DQ_31_IOF_IVAL, 46, GMC0_GMC_DQ_31_HS_SEL, 0, 0);

    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD91,GMC0_GMC_DQ_0_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD90,GMC0_GMC_DQ_1_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD89,GMC0_GMC_DQ_2_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD88,GMC0_GMC_DQ_3_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD87,GMC0_GMC_DQ_4_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD86,GMC0_GMC_DQ_5_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD85,GMC0_GMC_DQ_6_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD84,GMC0_GMC_DQ_7_HS_SEL, 0, 0);

    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD99,GMC0_GMC_DQ_8_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD98,GMC0_GMC_DQ_9_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD97,GMC0_GMC_DQ_10_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD96,GMC0_GMC_DQ_11_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD95,GMC0_GMC_DQ_12_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD94,GMC0_GMC_DQ_13_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD93,GMC0_GMC_DQ_14_HS_SEL, 0, 0);
    iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD92,GMC0_GMC_DQ_15_HS_SEL, 0, 0);

    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD146,GMC0_GMC_DQ_16_HS_SEL, 0, 0);
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD145,GMC0_GMC_DQ_17_HS_SEL, 0, 0);
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD144,GMC0_GMC_DQ_18_HS_SEL, 0, 0);
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD143,GMC0_GMC_DQ_19_HS_SEL, 0, 0);  // also JTAG_TMS
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD142,GMC0_GMC_DQ_20_HS_SEL, 0, 0);  // also JTAG_TCK
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD141,GMC0_GMC_DQ_21_HS_SEL, 0, 0);  // also JTAG_TDO
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD140,GMC0_GMC_DQ_22_HS_SEL, 0, 0);
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD139,GMC0_GMC_DQ_23_HS_SEL, 0, 0);

    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD154,GMC0_GMC_DQ_24_HS_SEL, 0, 0);
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD153,GMC0_GMC_DQ_25_HS_SEL, 0, 0);
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD152,GMC0_GMC_DQ_26_HS_SEL, 0, 0);
    // //iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD151,GMC0_GMC_DQ_27_HS_SEL, 0, 0);  // also UART_RX
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD150,GMC0_GMC_DQ_28_HS_SEL, 0, 0);    // also JTAG_TDI
    // //iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD149,GMC0_GMC_DQ_29_HS_SEL, 0, 0);  // also UART_TX
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD148,GMC0_GMC_DQ_30_HS_SEL, 0, 0);
    // iomux_ls_iof_pullup_cfg(IOMUX_BASE,PAD147,GMC0_GMC_DQ_31_HS_SEL, 0, 0);

    /*sram/nor config*/
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_CLK_IOF_OVAL, 46, GMC0_O_GMC_NPC_CLK_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NADV_IOF_OVAL, 46, GMC0_O_GMC_NPC_NADV_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NBL_0_IOF_OVAL, 46, GMC0_O_GMC_NPC_NBL_0_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NBL_1_IOF_OVAL, 46, GMC0_O_GMC_NPC_NBL_1_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NBL_2_IOF_OVAL, 46, GMC0_O_GMC_NPC_NBL_2_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NBL_3_IOF_OVAL, 46, GMC0_O_GMC_NPC_NBL_3_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NE_0_IOF_OVAL, 46, GMC0_O_GMC_NPC_NE_0_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NE_1_IOF_OVAL, 46, GMC0_O_GMC_NPC_NE_1_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NE_2_IOF_OVAL, 46, GMC0_O_GMC_NPC_NE_2_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NE_3_IOF_OVAL, 46, GMC0_O_GMC_NPC_NE_3_HS_SEL, 0, 0);
    // iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_SDR_CS_N_0_IOF_OVAL, 46, GMC0_SDR_CS_N_0_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NWE_IOF_OVAL, 46, GMC0_O_GMC_NPC_NWE_HS_SEL, 0, 0);
    iomux_ls_iof_oval_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NOE_IOF_OVAL, 46, GMC0_O_GMC_NPC_NOE_HS_SEL, 0, 0);

    // iomux_ls_iof_ival_cfg(IOMUX_BASE,GMC0_O_GMC_NPC_NWAIT_IOF_IVAL, 38, GMC0_O_GMC_NPC_NWAIT_HS_SEL, 0, 0);

    //PCRAM1_ZZ
    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_9_IOF_OVAL,56,LGPIO_IO_PORT_PINS_9_HS_SEL,0,0);
    LGPIO_Output_Enable(LGPIO,1<<9);
    LGPIO_WriteBit(LGPIO,1<<9,1);
    LGPIO_Mode(LGPIO,1<<9,PP);
    //CS_SW
    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_8_IOF_OVAL,59,LGPIO_IO_PORT_PINS_8_HS_SEL,0,0);
    LGPIO_Output_Enable(LGPIO,1<<8);
    LGPIO_WriteBit(LGPIO,1<<8,1);//set 1: ADDR 0 is PCRAM; set 0: ADDR 0 is SRAM
    LGPIO_Mode(LGPIO,1<<8,PP);

}
void exmc_pcram_init(void)
{
    gmc0_clk_en(ENABLE);

    gmc0_set_rst(DISABLE);
    gmc0_set_rst(ENABLE);

    gmc0_clk_div(40);

    PCRAM_iomux_config();
    // bank1
    REG32(GMC0_BASE + GMC_BCR_1) &= ((uint32_t)~(GMC_BCR_MBKEN_MASK | GMC_BCR_MUXEN_MASK | GMC_BCR_MTYP_MASK |
                                                GMC_BCR_MWID_MASK      | GMC_BCR_FACCEN_MASK   | GMC_BCR_BURSTEN_MASK  |
                                                GMC_BCR_WAITPOL_MASK   | GMC_BCR_CPSIZE_MASK    | GMC_BCR_WAITCFG_MASK  |
                                                GMC_BCR_WREN_MASK      | GMC_BCR_WAITEN_MASK   | GMC_BCR_EXTMOD_MASK   |
                                                GMC_BCR_ASYNCWAIT_MASK | GMC_BCR_CBURSTRW_MASK | GMC_BCR_CCLKEN_MASK | GMC_BCR_WFDIS_MASK));

    // sram 16bit width
    REG32(GMC0_BASE + GMC_BCR_1) |= (GMC_MBKEN_ENABLE
                                   | GMC_MUXEN_DISABLE
                                   | GMC_MTYP_SRAM
                                   | GMC_MWID_WIDTH_16
                                   | GMC_FACCEN_DISABLE
                                   | GMC_WREN_ENABLE
                                   | GMC_EXTMOD_ENABLE
                                   | GMC_CCLKEN_ENABLE
                                   | GMC_BCR_BMAP(0)
                                   | GMC_BCR_EXTEND(8));    // SRAM 1M-16bit

    REG32(GMC0_BASE + GMC_BTR_1) &= ((uint32_t)~(GMC_BTR_ADDSET_MASK  | GMC_BTR_ADDHLD_MASK | GMC_BTR_DATAST_MASK |
                                                GMC_BTR_BUSTURN_MASK | GMC_BTR_CLKDIV_MASK | GMC_BTR_DATLAT_MASK | GMC_BTR_ACCMOD_MASK | GMC_BTR_EARLYTIME_MASK));

    // mode A
    REG32(GMC0_BASE + GMC_BTR_1) |= (GMC_BTR_ADDSET(2)//4
                                   | GMC_BTR_ADDHLD(0)//0
                                   | GMC_BTR_DATAST(3)//4
                                   | GMC_BTR_BUSTURN(2)//10
                                   | GMC_BTR_CLKDIV(15)//15
                                   | GMC_BTR_DATLAT(0)//0
                                   | GMC_BTR_ACCMOD_A
                                   | GMC_BTR_EARLYTIME(1));//1

    REG32(GMC0_BASE + GMC_BWTR_1) &= ((uint32_t)~(GMC_BWTR_ADDSET_MASK  | GMC_BWTR_ADDHLD_MASK | GMC_BWTR_DATAST_MASK |
                                                GMC_BWTR_BUSTURN_MASK | GMC_BWTR_ACCMOD_MASK));

    REG32(GMC0_BASE + GMC_BWTR_1) |= (GMC_BWTR_ADDSET(2)//4
                                   | GMC_BWTR_ADDHLD(0)//0
                                   | GMC_BWTR_DATAST(3)//4
                                   | GMC_BWTR_BUSTURN(2)//10
                                   | GMC_BWTR_ACCMOD_A);

    REG32(GMC0_BASE + GMC_BCR_1) |= GMC_GMC_EN_ENABLE;
    //////////////////////////////////////////////PCRAM config
    typedef FlagStatus bit_status;
    uint32_t cfg_data = 0xC3DBCCA9;//0xC0DB4CB9;0xC3DBCCA9;
    //第2位：0~3，控制结晶电流
    //第5位：4~C，控制参考电阻
    //第7位：A是使用外部VGB,B是使用内部VBG
    bit_status bit_value;
    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_10_IOF_OVAL,55,LGPIO_IO_PORT_PINS_10_HS_SEL,0,0);//CFGC
    LGPIO_Output_Enable(LGPIO,1<<10);//CFGC
    LGPIO_WriteBit(LGPIO,1<<10,0);//CFGC
    LGPIO_Mode(LGPIO,1<<10,PP);//CFGC

    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_11_IOF_OVAL,54,LGPIO_IO_PORT_PINS_11_HS_SEL,0,0);//CFGD
    LGPIO_Output_Enable(LGPIO,1<<11);//CFGD
    LGPIO_Mode(LGPIO,1<<11,PP);//CFGD

    //PCRAM1_ZZ
    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_9_IOF_OVAL,56,LGPIO_IO_PORT_PINS_9_HS_SEL,0,0);//ZZ
    LGPIO_Output_Enable(LGPIO,1<<9);//ZZ
    LGPIO_WriteBit(LGPIO,1<<9,1);//ZZ
    LGPIO_Mode(LGPIO,1<<9,PP);//ZZ

	delay_1ms(1);
    uint32_t i =0;
	for(i=0;i<32;i++)
	{
		delay_1ms(10);
		bit_value = (bit_status)((cfg_data >> (31-i)) & 0x01);
        LGPIO_WriteBit(LGPIO,1<<11,(bit_status)bit_value);//CFGD
		delay_1ms(10);
        LGPIO_WriteBit(LGPIO,1<<10,1);//CFGC
		delay_1ms(20);
        LGPIO_WriteBit(LGPIO,1<<10,0);//CFGC
	}

    LGPIO_WriteBit(LGPIO,1<<9,0);//ZZ
    LGPIO_WriteBit(LGPIO,1<<11,1);//CFGD
    pcram_wakeup(1);
    delay_1ms(10);
}

void spi_pcram_init(void)
{
    // lgpio_clk_en(ENABLE);

    // lgpio_set_rst(DISABLE);
    // lgpio_set_rst(ENABLE);

    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_18_IOF_OVAL,124,LGPIO_IO_PORT_PINS_18_HS_SEL,0,0);//CS
    LGPIO_Output_Enable(LGPIO,1<<18);//CS
    LGPIO_WriteBit(LGPIO,1<<18,1);//CS
    LGPIO_Mode(LGPIO,1<<18,PP);//CS

    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_26_IOF_OVAL,137,LGPIO_IO_PORT_PINS_26_HS_SEL,0,0);//SCK
    LGPIO_Output_Enable(LGPIO,1<<26);//SCK
    LGPIO_WriteBit(LGPIO,1<<26,1);//SCK
    LGPIO_Mode(LGPIO,1<<26,PP);//SCK

    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_27_IOF_OVAL,138,LGPIO_IO_PORT_PINS_27_HS_SEL,0,0);//MOSI
    LGPIO_Output_Enable(LGPIO,1<<27);//MOSI
    LGPIO_WriteBit(LGPIO,1<<27,1);//MOSI
    LGPIO_Mode(LGPIO,1<<27,PP);//MOSI

    iomux_ls_iof_ival_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_28_IOF_IVAL,134,LGPIO_IO_PORT_PINS_28_HS_SEL,0,0);//MISO
    LGPIO_Input_Enable(LGPIO,1 << 28);//MISO


    //////////////////////////////////////////////PCRAM config
    typedef FlagStatus bit_status;
    uint32_t cfg_data = 0xC3DBCCA9;//0xC0DB4CB9;0xC3DBCCA9;
    //第2位：0~3，控制结晶电流
    //第5位：4~C，控制参考电阻
    //第7位：A是使用外部VGB,B是使用内部VBG
    bit_status bit_value;
    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_24_IOF_OVAL,167,LGPIO_IO_PORT_PINS_24_HS_SEL,0,0);//CFGC2
    LGPIO_Output_Enable(LGPIO,1<<24);//CFGC
    LGPIO_WriteBit(LGPIO,1<<24,0);//CFGC
    LGPIO_Mode(LGPIO,1<<24,PP);//CFGC

    iomux_ls_iof_oval_cfg(IOMUX_BASE,LGPIO_IO_PORT_PINS_25_IOF_OVAL,168,LGPIO_IO_PORT_PINS_25_HS_SEL,0,0);//CFGD2
    LGPIO_Output_Enable(LGPIO,1<<25);//CFGD
    LGPIO_Mode(LGPIO,1<<25,PP);//CFGD

	delay_1ms(1);
  uint32_t i =0;
	for(i=0;i<32;i++)
	{
		delay_1ms(10);
		bit_value = (bit_status)((cfg_data >> (31-i)) & 0x01);
        LGPIO_WriteBit(LGPIO,1<<25,(bit_status)bit_value);//CFGD
		delay_1ms(10);
        LGPIO_WriteBit(LGPIO,1<<24,1);//CFGC
		delay_1ms(20);
        LGPIO_WriteBit(LGPIO,1<<24,0);//CFGC
	}

    LGPIO_WriteBit(LGPIO,1<<25,1);//CFGD
    delay_1ms(10);
}

//SPI可以同时读取和写入数据，因此一个函数即可满足要求
uint8_t SPI_PCRAM_ReadWriteByte(uint8_t txData)
{
    uint8_t i;
    uint8_t rxData = 0;

    for(i = 0; i < 8; i++)
    {
        SPI_SCK_0;
        delay_1us(SPI_TIME_US);
        //数据发送
        if(txData & 0x80){
            SPI_MOSI_1;
        }else{
            SPI_MOSI_0;
        }
        txData <<= 1;
        delay_1us(SPI_TIME_US);

        SPI_SCK_1;
        delay_1us(SPI_TIME_US);
        //数据接收
        rxData <<= 1;
        if(SPI_READ_MISO){
            rxData |= 0x01;
        }
        delay_1us(SPI_TIME_US);
    }
    SPI_SCK_0;

    return rxData;
}

uint8_t SPI_PCRAM_ReadByte(void)
{
    return SPI_PCRAM_ReadWriteByte(Dummy_Byte);
}

void SPI_PCRAM_WriteByte(uint8_t txData)
{
    (void)SPI_PCRAM_ReadWriteByte(txData);
}

void SPI_PCRAM_WriteAddr(uint32_t pcramAddr)
{
  uint8_t i;
  for(i = 0; i < 19; i++)
  {
      SPI_SCK_0;
      delay_1us(SPI_TIME_US);
      //数据发送
      if(pcramAddr & 0x40000){
          SPI_MOSI_1;
      }else{
          SPI_MOSI_0;
      }
      pcramAddr <<= 1;
      delay_1us(SPI_TIME_US);
      SPI_SCK_1;
      delay_1us(SPI_TIME_US);
      delay_1us(SPI_TIME_US);
  }
  SPI_SCK_0;
}
void SPI_PCRAM_Wip(void)
{
    uint8_t temp = 0;
    SPI_PCRAM_CS_ON;
    SPI_PCRAM_WriteByte(0x05);
    do {
        temp = SPI_PCRAM_ReadByte() & 0x1;
    }while(temp);
    SPI_PCRAM_CS_OFF;
}
void SPI_PCRAM_WriteEnable(void)
{
	SPI_PCRAM_CS_ON;
  SPI_PCRAM_WriteByte(0x06);
	SPI_PCRAM_CS_OFF;
}
void SPI_PCRAM_BuffWrite(uint8_t* buf, uint32_t addr, uint8_t len)
{
  SPI_PCRAM_WriteEnable();
	SPI_PCRAM_CS_ON;
	SPI_PCRAM_WriteByte(0x02);
  SPI_PCRAM_WriteAddr(addr);
  for(int i = 0; i < len; i++) {
    SPI_PCRAM_WriteByte(buf[i]);
  }
	SPI_PCRAM_CS_OFF;
  SPI_PCRAM_Wip();
}
void SPI_PCRAM_BuffRead(uint8_t* buf, uint32_t addr, uint8_t len)
{
	SPI_PCRAM_CS_ON;
	SPI_PCRAM_WriteByte(0x03);
  SPI_PCRAM_WriteAddr(addr);
  SPI_PCRAM_WriteByte(0x00);
  SPI_PCRAM_WriteByte(0x00);
  SPI_PCRAM_WriteByte(0x00);
  SPI_PCRAM_WriteByte(0x00);
  SPI_PCRAM_WriteByte(0x00);
  SPI_PCRAM_WriteByte(0x00);
  for(int i = 0; i < len; i++) {
    buf[i] = SPI_PCRAM_ReadByte();
  }
	SPI_PCRAM_CS_OFF;
}
uint8_t pcram_sleep(uint8_t num)
{
  switch(num)
  {
    case 1:
    {
      LGPIO_WriteBit(LGPIO,1<<9,0);//ZZ
      delay_1ms(10);
      return 1;
      break;
    }
    case 2:
    {
      return 2;
      break;
    }
    default:
    {
      return 0;
    }
  }
}
uint8_t pcram_wakeup(uint8_t num)
{
    switch(num)
  {
    case 1:
    {
      LGPIO_WriteBit(LGPIO,1<<9,1);//ZZ
      delay_1ms(10);
      return 1;
      break;
    }
    case 2:
    {
      return 2;
      break;
    }
    default:
    {
      return 0;
    }
  }
}
void exmc_pcram_clear(uint32_t WriteAddr, uint32_t NumByteToWrite)
{
//  delay_1ms(1000);
  uint32_t i = 0;
  uint32_t WriteRealAddr=0;
  uint32_t Write32_num=0;
  uint32_t Temp_Value=0;
  uint8_t Addr_start_Offset = 0;
  uint8_t Addr_end_Offset = 0;
  uint32_t Num1, Num2, Num3, Num4;
  Addr_start_Offset=WriteAddr%4;
  Addr_end_Offset=(4-(Addr_start_Offset+NumByteToWrite)%4)%4;
  if(Addr_end_Offset)
  {
    Write32_num=(Addr_start_Offset+NumByteToWrite)/4+1;
  }
  else
  {
    Write32_num=(Addr_start_Offset+NumByteToWrite)/4;
  }
  WriteRealAddr = WriteAddr-Addr_start_Offset;
  if(Write32_num==1)
  {
    switch (Addr_start_Offset)
    {
      case 0:
      {
        if(Addr_end_Offset==0)
        {
          REG32(WriteRealAddr) = 0;
        }
        else if(Addr_end_Offset==1)
        {
          Num1=0;
          Num2=0;
          Num3=0;
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else if(Addr_end_Offset==2)
        {
          Num1=0;
          Num2=0;
          Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else
        {
          Num1=0;
          Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
          Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        break;
      }
      case 1:
      {
        if(Addr_end_Offset==0)
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=0;
          Num3=0;
          Num4=0;
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else if(Addr_end_Offset==1)
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=0;
          Num3=0;
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=0;
          Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        break;
      }
      case 2:
      {
        if(Addr_end_Offset==0)
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
          Num3=0;
          Num4=0;
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        else
        {
          Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
          Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
          Num3=0;
          Num4=(REG32(WriteRealAddr)&0x000000FF);
          Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
          REG32(WriteRealAddr) = Temp_Value;
        }
        break;
      }
      case 3:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
        Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
        Num4=0;
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
    }
  }
  else
  {
    switch (Addr_start_Offset)
    {
      case 0:
      {
        REG32(WriteRealAddr) = 0;
        break;
      }
      case 1:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=0;
        Num3=0;
        Num4=0;
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
      case 2:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
        Num3=0;
        Num4=0;
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
      case 3:
      {
        Num1=((REG32(WriteRealAddr)&0xFF000000)>>24);
        Num2=((REG32(WriteRealAddr)&0x00FF0000)>>16);
        Num3=((REG32(WriteRealAddr)&0x0000FF00)>>8);
        Num4=0;
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr) = Temp_Value;
        break;
      }
    }
    for(i=1;i<Write32_num-1;i++)
    {
      REG32(WriteRealAddr+i*4) = 0;
    }
    switch (Addr_end_Offset)
    {
      case 0:
      {
        REG32(WriteRealAddr+(Write32_num-1)*4) = 0;
        break;
      }
      case 1:
      {
        Num1=0;
        Num2=0;
        Num3=0;
        Num4=(REG32(WriteRealAddr+(Write32_num-1)*4)&0x000000FF);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr+(Write32_num-1)*4) = Temp_Value;
        break;
      }
      case 2:
      {
        Num1=0;
        Num2=0;
        Num3=((REG32(WriteRealAddr+(Write32_num-1)*4)&0x0000FF00)>>8);
        Num4=(REG32(WriteRealAddr+(Write32_num-1)*4)&0x000000FF);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr+(Write32_num-1)*4) = Temp_Value;
        break;
      }
      case 3:
      {
        Num1=0;
        Num2=((REG32(WriteRealAddr+(Write32_num-1)*4)&0x00FF0000)>>16);
        Num3=((REG32(WriteRealAddr+(Write32_num-1)*4)&0x0000FF00)>>8);
        Num4=(REG32(WriteRealAddr+(Write32_num-1)*4)&0x000000FF);
        Temp_Value=(Num1<<24) | (Num2<<16) | (Num3<<8) | Num4;
        REG32(WriteRealAddr+(Write32_num-1)*4) = Temp_Value;
        break;
      }
    }
  }
}



